package ir2

import (
	"sort"
	"strings"

	"gitee.com/u-language/u-language/ucom/ast"
	"gitee.com/u-language/u-language/ucom/errcode"
)

// Ir2 表示一个可以包含ir2定义的ir指令的类型
type Ir2 interface {
	String() string
	ir2()
}

var _ Ir2 = (*File)(nil)

type File struct {
	//全局声明
	GlobalDecl []ast.Node
	//指令
	Ir []IrNode
	//变量初始化
	VarInit []IrNode
	// 临时变量
	tmpVar autoVar
	//现有临时变量
	tmpVarStr string
	//包名
	PackageName string
	// 文件名
	FileName string
	//是否有自定义init函数
	HaveInitFunc bool
	//是否在函数内
	InFunc   bool
	Sbt      *ast.Sbt
	FuncInfo *ast.FuncInfo
	//临时变量的保存地点
	tmp *[]IrNode
	//错误处理上下文
	Errctx *errcode.ErrCtx
}

func NewFile(t *ast.Tree, Errctx *errcode.ErrCtx) *File {
	ret := new(File)
	ret.PackageName, ret.HaveInitFunc, ret.Sbt, ret.FileName, ret.tmp, ret.Errctx = t.PackageName, t.IsInitFunc.Load(), t.Sbt, t.Filename, &ret.Ir, Errctx
	NodeToIr(ret, t.Nodes)
	sort.SliceStable(ret.VarInit, func(i, j int) bool {
		return ret.VarInit[i].LineNum < ret.VarInit[j].LineNum
	})
	return ret
}

// getTmpVar 返回一个临时变量
// 如果 old == true , 返回之前一次调用返回的临时变量
func (f *File) getTmpVar(old bool, LineNum int) string {
	if old {
		return f.tmpVarStr
	}
	f.tmpVarStr = f.tmpVar.Get()
	v := NewIr(TmpVarOP, LineNum)
	v.Arg1Obj = f.tmpVarStr
	(*f.tmp) = append((*f.tmp), v)
	return f.tmpVarStr
}

func (f *File) String() string {
	var buf strings.Builder
	buf.WriteString("ir2.File{\n全局声明：\n")
	for _, v := range f.GlobalDecl {
		buf.WriteString(v.String())
		buf.WriteString("\n")
	}
	buf.WriteString("\n变量初始化：\n")
	for _, v := range f.VarInit {
		buf.WriteString(v.String())
		buf.WriteString("\n")
	}
	buf.WriteString("\n\n指令：\n")
	for _, v := range f.Ir {
		buf.WriteString(v.String())
		buf.WriteString("\n")
	}
	buf.WriteString("}")
	return buf.String()
}

func (f *File) ir2() {}

// toS 将转换的结果保存到ret
func (f *File) toS(ret *[]IrNode, F func()) {
	old := f.Ir
	f.Ir = *ret
	F()
	*ret = f.Ir
	f.Ir = old
}
